home *** CD-ROM | disk | FTP | other *** search
- /*
- * wKeys-Handler.c Input Handler for wKeyw, which moves and activates
- * windows and screensin response to keystrokes
- *
- * Copyright (c) 1987,1988 by Davide P. Cervone
- * You may use this code provided this copyright notice is left intact.
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <devices/inputevent.h>
- #include <intuition/intuitionbase.h>
-
- #include "wKeys.h"
-
- static char *program = "wKeys-Handler";
- static int version = 3;
- static char *date = "January 1988";
- static char *author = "Copyright (c) 1987,1988 by Davide P. Cervone";
-
- extern struct Layer *WhichLayer();
- extern struct IntuiMessage *GetMsg();
- extern struct IntuiMessage *AllocMem();
- extern void myHandlerStub();
-
- #define WINDOW(layer) ((struct Window *)((layer)->Window))
-
- #define SCREENTOP\
- (theScreen->TopEdge << ((theScreen->ViewPort.Modes & LACE)? 0: 1))
-
- #define IMSIZE ((ULONG)sizeof(struct IntuiMessage))
- #define NEWMESSAGE(m) (m = AllocMem(IMSIZE,MEMF_PUBLIC | MEMF_CLEAR))
- #define FREEMESSAGE(m) FreeMem(m,IMSIZE);
-
- struct IntuitionBase *IntuitionBase = NULL;
- struct LayersBase *LayersBase = NULL;
- struct SysBase *SysBase = NULL;
-
- static struct HotKey *Key = NULL;
- static int KeyCount = 0;
- static struct MsgPort *ReplyPort = NULL;
-
- /*
- * Setup()
- *
- * wKeys calls LoadSeg() to get this handler into memory. The segment
- * that it gets points to this routine. wKeys calls Setup() and
- * passes the IntuitionBase, LayersBase and SysBase pointers that it
- * has initialized (with OpenLibrary()). wKeys also passes the KeyArray
- * and KeyCount which hold the key bindings. Setup returns a pointer to
- * the actual input handler, which wKeys installs, and sets the version
- * number so that hotKey can report the handler's version.
- */
-
- long Setup(Ibase,Lbase,Sbase,theKeys,Count,Port,VersionPtr)
- struct IntuitionBase *Ibase;
- struct LayersBase *Lbase;
- struct SysBase *Sbase;
- struct HotKey *theKeys;
- struct MsgPort *Port;
- int *VersionPtr;
- int Count;
- {
- IntuitionBase = Ibase;
- LayersBase = Lbase;
- SysBase = Sbase;
- Key = theKeys;
- KeyCount = Count;
- ReplyPort = Port;
- *VersionPtr = version;
- return((long) &myHandlerStub);
- }
-
- /*
- * TopWindow()
- *
- * Find the top window of the specified screen. Start at the top layer of
- * the screen and move backward as long as the layer exists and has no
- * window connected to it. Return the window associated with the final
- * layer, if any.
- */
-
- static struct Window *TopWindow(theScreen)
- struct Screen *theScreen;
- {
- struct Window *theWindow = NULL;
- struct Layer *theLayer;
-
- theLayer = theScreen->LayerInfo.top_layer;
- while (theLayer && WINDOW(theLayer) == NULL) theLayer = theLayer->back;
- if (theLayer) theWindow = WINDOW(theLayer);
- return(theWindow);
- }
-
- /*
- * BottomWindow()
- *
- * Find the bottom window of the specified screen. Start at the top layer
- * and as long as the layer exists, go to the next layer back. If the
- * layer has a window attached, consider that to be the bottom window until
- * a lower one is found.
- */
-
- static struct Window *BottomWindow(theScreen)
- struct Screen *theScreen;
- {
- struct Window *theWindow = NULL;
- struct Layer *theLayer = theScreen->LayerInfo.top_layer;
-
- while (theLayer)
- {
- if (WINDOW(theLayer) && isIconified(WINDOW(theLayer)) == FALSE)
- theWindow = WINDOW(theLayer);
- theLayer = theLayer->back;
- }
- return(theWindow);
- }
-
- /*
- * NextWindow()
- *
- * Find the next window below the specified window (wrap arround to the top
- * if the window is the bottom one). Start with the window's layer and go
- * back until a layer with a window is found, or no more layers exist. If
- * a window was found, return it, otherwise, use the top window.
- */
-
- static struct Window *NextWindow(theWindow)
- struct Window *theWindow;
- {
- struct Layer *theLayer = theWindow->WLayer;
-
- do
- theLayer = theLayer->back;
- while (theLayer && (WINDOW(theLayer) == NULL ||
- isIconified(WINDOW(theLayer))));
- if (theLayer)
- theWindow = WINDOW(theLayer);
- else
- theWindow = TopWindow(theWindow->WScreen);
- return(theWindow);
- }
-
- /*
- * PreviousWindow()
- *
- * Find the window that is on top of the specified window (or NULL if there
- * are no windows above it). Start with the window's layer, and move to
- * the layer in front until a layer with a (different) window is found, or
- * until no more layers exist. If a window was found, return it, otherwise
- * return NULL.
- */
-
- static struct Window *PreviousWindow(theWindow)
- struct Window *theWindow;
- {
- struct Layer *theLayer = theWindow->WLayer;
-
- do
- theLayer = theLayer->front;
- while (theLayer && (WINDOW(theLayer) == NULL ||
- WINDOW(theLayer) == theWindow));
- if (theLayer)
- theWindow = WINDOW(theLayer);
- else
- theWindow = NULL;
- return(theWindow);
- }
-
- /*
- * BackScreenToFront()
- *
- * Bring the bottom-most screen to the top, and activate its top window.
- * While there is a screen following the current one, move the the next screen.
- * Bring that screen to the front and find its top window. If one was found,
- * activate the window.
- */
-
- static void BackScreenToFront()
- {
- struct Screen *theScreen = IntuitionBase->FirstScreen;
- struct Window *theWindow;
-
- if (theScreen)
- {
- while (theScreen->NextScreen) theScreen = theScreen->NextScreen;
- ScreenToFront(theScreen);
- theWindow = TopWindow(theScreen);
- if (theWindow) ActivateWindow(theWindow);
- }
- }
-
- /*
- * FrontScreenToBack()
- *
- * Move the top screen to the back and activate the top window on the new
- * top screen.
- */
-
- static void FrontScreenToBack()
- {
- struct Screen *theScreen = IntuitionBase->FirstScreen;
- struct Window *theWindow;
-
- if (theScreen)
- {
- ScreenToBack(theScreen);
- theScreen = IntuitionBase->FirstScreen;
- if (theScreen)
- {
- theWindow = TopWindow(theScreen);
- if (theWindow) ActivateWindow(theWindow);
- }
- }
- }
-
- /*
- * ActivatePreviousWindow()
- *
- * Get the window previous to the current window (if none, then get the
- * bottom window in the active screen), and activate that window.
- */
-
- static void ActivatePreviousWindow()
- {
- struct Window *theWindow = PreviousWindow(IntuitionBase->ActiveWindow);
-
- if (theWindow == NULL) theWindow = BottomWindow(IntuitionBase->ActiveScreen);
- if (theWindow) ActivateWindow(theWindow);
- }
-
- /*
- * ActivateNextWindow()
- *
- * Get the window below the current window and activate it.
- */
-
- static void ActivateNextWindow()
- {
- struct Window *theWindow = NextWindow(IntuitionBase->ActiveWindow);
-
- if (theWindow) ActivateWindow(theWindow);
- }
-
- /*
- * CurrentWindowToBack()
- *
- * Send the current window to the back of the list.
- */
-
- static void CurrentWindowToBack()
- {
- struct Window *theWindow = IntuitionBase->ActiveWindow;
-
- if (theWindow && (theWindow->Flags & BACKDROP) == 0)
- WindowToBack(theWindow);
- }
-
- /*
- * CurrentWindowToFront()
- *
- * Send the current window to the top of the list.
- */
-
- static void CurrentWindowToFront()
- {
- struct Window *theWindow = IntuitionBase->ActiveWindow;
-
- if (theWindow) WindowToFront(theWindow);
- }
-
- /*
- * BackWindowToFront()
- *
- * Move the bottom window to the top and activate it. Get the bottom window,
- * skipping over backdrop windows. If one is found, bring it to the front,
- * and activate it.
- */
-
- static void BackWindowToFront()
- {
- struct Window *theWindow = BottomWindow(IntuitionBase->ActiveScreen);
-
- if (theWindow)
- {
- while (theWindow && (theWindow->Flags & BACKDROP))
- theWindow = PreviousWindow(theWindow);
- if (theWindow)
- {
- WindowToFront(theWindow);
- ActivateWindow(theWindow);
- }
- }
- }
-
- /*
- * FrontWindowToBack()
- *
- * Move the top window to the back, and activate the new top window.
- * Get the top window, and then the window following it. Send the top window
- * to the back, and activate the next window.
- */
-
- static void FrontWindowToBack()
- {
- struct Window *theWindow = TopWindow(IntuitionBase->ActiveScreen);
- struct Window *nextWindow = NextWindow(theWindow);
-
- if (theWindow && (theWindow->Flags & BACKDROP) == 0)
- {
- WindowToBack(theWindow);
- if (nextWindow) ActivateWindow(nextWindow);
- }
- }
-
- /*
- * CloseCurrentWindow()
- *
- * If the current window has the CLOSEWINDOW IDCMP flag, then
- * send it a CLOSEWINDOW IDCMP message. Unfortunately, the workbench
- * has the CLOSWINDOW flag set, and it crashes if you send it a close
- * message; therefore, CloseCurrentWindow will not sent a CLOSWINDOW
- * event to a BACKDROP window. This seemed the easiest way to rule out
- * the workbench without too much overhead.
- *
- * The message will be replied to the ReplyPort, which is checked in the
- * input handler. Any messages that get returned are freed.
- */
-
- static void CloseCurrentWindow()
- {
- struct Window *theWindow = IntuitionBase->ActiveWindow;
- struct IntuiMessage *theMessage;
-
- if (theWindow && (theWindow->IDCMPFlags & CLOSEWINDOW) &&
- (theWindow->Flags & BACKDROP) == 0)
- {
- if (NEWMESSAGE(theMessage))
- {
- theMessage->Class = CLOSEWINDOW;
- theMessage->IDCMPWindow = theWindow;
- theMessage->ExecMessage.mn_ReplyPort = ReplyPort;
- PutMsg(theWindow->UserPort,theMessage);
- }
- }
- }
-
- /*
- * WindowToIcon()
- *
- * Iconify the current window if wIconify is running.
- */
-
- static void WindowToIcon()
- {
- struct Window *theWindow = IntuitionBase->ActiveWindow;
-
- if (theWindow) wIconifyWindow(theWindow);
- }
-
- /*
- * IconToWindow()
- *
- * Restore the selected wIconify icon to a window. The workbench must
- * be the active window, and wIconify must be running, and a window icon
- * must be selected.
- */
-
- static void IconToWindow()
- {
- wRestoreWindow(NULL);
- }
-
- /*
- * SelectNextIcon()
- *
- * Tells wIconify to select the next window icon on the workbench. If no
- * icon is selected, then select the first icon.
- */
-
- static void SelectNextIcon()
- {
- wNextIcon();
- }
-
- /*
- * Array of functions that perform the different actions associated with
- * the hot-keys. These are called by the handler routine.
- */
-
- typedef void (*FUNCTION)();
-
- static FUNCTION Action[] =
- {
- NULL,
- &BackScreenToFront,
- &FrontScreenToBack,
- &ActivatePreviousWindow,
- &ActivateNextWindow,
- &CurrentWindowToBack,
- &CurrentWindowToFront,
- &BackWindowToFront,
- &FrontWindowToBack,
- &CloseCurrentWindow,
- &WindowToIcon,
- &IconToWindow,
- &SelectNextIcon
- };
-
- /*
- * myHandler()
- *
- * This is the input handler.
- * First check if there are any returned CLOSEWINDOW events, then,
- * For each event in the event list:
- * If the event is a raw key event, then
- * make the KeyCode longword for that event's code and qualifier,
- * binary search the Key[] array for a matching entry (only consider
- * the qualifiers specified by the KeyMask). Since most keys pressed
- * will NOT match a hot-key, we want the search to be as fast as
- * possible, so we use a binary search rather than a linear search.
- * set NoHotKey if the key is not a hot key.
- * if the key was not a hot key,
- * go on to the next key
- * otherwise,
- * perform the function for the specified hot key,
- * remove the hot key from the event list.
- *
- * When all the events have been checked, return the event list so that
- * Intuition can do its thing.
- */
-
- struct InputEvent *myHandler(EventList,data)
- struct InputEvent *EventList;
- APTR data;
- {
- register struct InputEvent **EventPtr = &EventList;
- register struct InputEvent *theEvent;
- register long theKey;
- register short Num,Min,Max;
- register long NoHotKey;
- struct IntuiMessage *theMessage;
-
- while (theMessage = GetMsg(ReplyPort)) FREEMESSAGE(theMessage);
-
- Forbid();
- while((theEvent = *EventPtr) != NULL)
- {
- NoHotKey = TRUE;
- if (theEvent->ie_Class == IECLASS_RAWKEY)
- {
- theKey = KEY(theEvent);
- Max = KeyCount; Min = -1;
- while ((Num = (Min + Max) >> 1) != Min &&
- (NoHotKey = (theKey & Key[Num].hk_KeyMask) -
- Key[Num].hk_KeyCode) != 0)
- if (NoHotKey > 0) Min = Num; else Max = Num;
- }
- if (NoHotKey)
- {
- EventPtr = &(theEvent->ie_NextEvent);
- } else {
- (*(Action[Key[Num].hk_Action]))();
- *EventPtr = theEvent->ie_NextEvent;
- }
- }
- Permit();
- return(EventList);
- }
-